﻿#include "qterminalscreen.h"
#include <QFontMetrics>
#include <QDebug>
#include <QDateTime>
#include <qmath.h>
#include <QMutex>
QMutex mutex;
#undef print
#define print qDebug()

qTerminalScreen::qTerminalScreen()
{
    this->screen_top=0;
    this->screen_bottom=this->scroll_bottom=0;
    this->screenBufSize=10000;

    lineContent = new _lineChars[screenBufSize+1];

    this->col_max=120;
    this->font  = QFont("consolas",10);
    QFontMetrics fontMetrics(font);
    this->fontHeight = fontMetrics.height();
    this->fontWidth = fontMetrics.width('A');
    timer.setSingleShot(false);
    timer.setInterval(100);
    const char *date_tmp = QDateTime::currentDateTime().toString("[hh:mm:ss]").toStdString().c_str();
    memcpy(date,date_tmp,sizeof(date));
    connect(&timer,&QTimer::timeout,this,[=](){
         const char *date_tmp = QDateTime::currentDateTime().toString("[hh:mm:ss]").toStdString().c_str();
         memcpy(date,date_tmp,sizeof(date));
    });
    timer.start();
}

qTerminalScreen::~qTerminalScreen()
{
    if(lineContent)
    {
        delete[] lineContent;
    }
}


void qTerminalScreen::getLineNumContent(int row) const
{
    char line[30]={0};
    if(row>99999)
    {
        line[0]='9';
        line[1]='9';
        line[2]='9';
        line[3]='9';
        line[4]='9';
        line[5]=' ';
        line[6]=' ';
    }
    else
    {
        itoa(row,line,10);
    }
    memcpy((void*)&date[10],line,7);

}

int qTerminalScreen::getLeftMargin() const
{
    return 17;
}

void qTerminalScreen::replace(char ch, quint32 row, int column,qTerminalFont &terminalFont)
{
    int _row=0,len=0;
    len = getLeftMargin();
    getLineNumContent(row);
    column += len;
    // QVector<qTerminalChar*> _lineChars;
    if(row+1>=this->screenBufSize)
        this->row_over = true;//溢出了
    row = row%this->screenBufSize;

    if(this->rowMaxCount>this->row_count)
    {
        _row = this->rowMaxCount-this->row_count;
        if(lineContent[row].size()>0)
        {
            lineContent[row].resize(0);
        }
        this->row_count +=_row;
        if(this->rowMaxCount>this->screen_bottom && this->scroll_showflag==false)
        {
            this->scroll_showflag = true;//大于bottom 允许显示滚动条
            emit setScrollValue(0,this->screen_bottom,this->screen_range,this->screen_bottom);
        }
        if(this->scroll_showflag)
        {
            if(!wheelFlag)
            {
                mutex.lock();
                this->screen_bottom=(this->rowMaxCount)%this->screenBufSize;//显示内容不能大于滚动区域最大值
//                if(this->screen_bottom-this->screen_range<0)
//                {
//                    this->screen_top=this->screenBufSize -this->screen_range;
//                }
//                else
//                {
//                    this->screen_top = (this->screen_bottom-this->screen_range)%this->screenBufSize;
//                }
                if((int)this->screen_bottom-(int)this->screen_range<0)
                {
                    this->screen_top=this->screen_bottom+this->screenBufSize -(this->screen_range-this->screen_bottom);
                }
                else
                {
                    this->screen_top = (this->screen_bottom-this->screen_range)%this->screenBufSize;
                }
                mutex.unlock();
            }
        }
        if(this->scroll_showflag && !wheelFlag)
        {
            if(this->scroll_bottom<this->screen_bottom && this->scroll_bottom!=this->screenBufSize)
            {
                this->scroll_bottom = this->screen_bottom;
            }
            emit setScrollValue(0,this->scroll_bottom,this->screen_range,this->scroll_bottom);
        }
            
    }
    if(column>=lineContent[row].size())
    {
        //print<<__func__<<__LINE__<<column<<len<<lineContent[row].size()<<arrary;
        if(lineContent[row].size()==0)
        { 
            lineContent[row].resize(column+1);

            for (int i = 0; i < len; i++)
            {
                qTerminalChar& lines = lineContent[row][i];
                lines.ch = date[i];
            }
            
        }
        else
        {
            lineContent[row].resize(column+1);
        }
    }
    if(ch!='\x0')
    {
        qTerminalChar& lines = lineContent[row][column];
        lines.ch = ch;

        lines.terminalFont = terminalFont;
    }
    
    emit updateSignal();
    return;
}



void qTerminalScreen::clearToEnd(quint32 row, int column)
{
    column += getLeftMargin();
    // QVector<qTerminalChar*> _lineChars;
    if(row+1>=this->screenBufSize)
        this->row_over = true;//溢出了
    row = row%this->screenBufSize;

    lineContent[row].resize(column);
    emit updateSignal();
}

void qTerminalScreen::clearScreen(quint32 row)
{
    int len = getLeftMargin();
    row = row%this->screenBufSize;

    while(1)
    {
        lineContent[row].resize(0);
        row++;
        row = row%this->screenBufSize;
        if(row>=this->getRowMax()%this->screenBufSize)
            break;
    }
    
    emit updateSignal();
}

QPoint qTerminalScreen::cursorPosition() const
{
    QPoint position;
    int row_overCount=0;
    quint32 i=this->getTop();
    if(i>=this->getScreenBufSize())
        i=this->getScreenBufSize()-1;
    while(1)
    {
        _lineChars& lines = this->lineContent[i];
        if((quint32)lines.size()>this->getColMax())
        {
            row_overCount += (int)((float)lines.size()/(float)this->getColMax());
        }
        if(i==this->getBottom()%this->getScreenBufSize())
            break;
        i++;
        i = i%this->getScreenBufSize();
        
    }

    if(this->getCol()+this->getLeftMargin()>this->getColMax())
    {
        position.setX((
            (this->getCol()+this->getLeftMargin())%this->getColMax()+
            this->getLeftMargin()
        )*fontWidth);
    }
    else
    {
        position.setX((
            (this->getCol()+this->getLeftMargin())%this->getColMax()
        )*fontWidth);
    }
    row_overCount = row_overCount>0?row_overCount:row_overCount;
    //print<<__FUNCTION__<<__LINE__<<qAbs(this->getRow()%this->getScreenBufSize()-this->getTop())<<(this->getRow()%this->getScreenBufSize()-this->getTop());
    int y=0;
    if (this->getRow()%this->getScreenBufSize()>this->getTop())
    {
        y = this->getRow()%this->getScreenBufSize()-this->getTop();
    }
    else
    {
        y = this->getRow()%this->getScreenBufSize() + this->getScreenBufSize()-this->getTop();
    }
    
    position.setY( (y+row_overCount)*fontHeight);
    return position;
}


void qTerminalScreen::scrollHandle(int tmp)
{
    if(this->screenBufSize==0)
        return;
    this->wheelFlag = true;//禁止数据更新

    print<<__func__<<scroll_current<<tmp<<this->screen_top<<this->screen_bottom<<this->screen_range<<this->getRowMax()<<this->scroll_bottom;
    if(scroll_current==0 && tmp>0)
        return;
    emit updateSignal();
    if(scroll_current+this->screen_range-tmp==this->scroll_bottom && tmp < 0)
    {
        mutex.lock();
        this->screen_bottom=(this->getRowMax())%this->screenBufSize;//显示内容不能大于滚动区域最大值
        if((int)this->screen_bottom-(int)this->screen_range<0)
        {
            this->screen_top=this->screen_bottom+this->screenBufSize -(this->screen_range-this->screen_bottom);
        }
        else
        {
            this->screen_top = (this->screen_bottom-this->screen_range)%this->screenBufSize;
        }
        this->wheelFlag = false;//允许数据更新
        mutex.unlock();
        return;
    }

    mutex.lock();
    if(this->screen_bottom==this->getRowMax()%this->getScreenBufSize() && tmp < 0)
    {
        mutex.unlock();
        return;
    }
    scrollChangedValue += tmp;
    if((int)this->screen_bottom-tmp<0)
    {
        this->screen_bottom = (this->screen_bottom+this->screenBufSize - (tmp-this->screen_bottom))%this->getScreenBufSize();
    }
    else
    {
        this->screen_bottom=(this->screen_bottom-tmp)%this->screenBufSize;//显示内容不能大于滚动区域最大值
    }
    if((int)this->screen_bottom-(int)this->screen_range<0)
    {
        this->screen_top=this->screen_bottom+this->screenBufSize -(this->screen_range-this->screen_bottom);
    }
    else
    {
        this->screen_top = (this->screen_bottom-this->screen_range)%this->screenBufSize;
    }
    mutex.unlock();
}


